package com.carbohydrate42.kotlin_compose_demo.compose

import android.content.Context
import android.util.Log
import android.widget.Toast
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import com.carbohydrate42.kotlin_compose_demo.constant.Common
import com.carbohydrate42.kotlin_compose_demo.util.DebugUtil
import org.eclipse.paho.android.service.MqttAndroidClient
import org.eclipse.paho.client.mqttv3.IMqttActionListener
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken
import org.eclipse.paho.client.mqttv3.IMqttToken
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended
import org.eclipse.paho.client.mqttv3.MqttConnectOptions
import org.eclipse.paho.client.mqttv3.MqttException
import org.eclipse.paho.client.mqttv3.MqttMessage

/**
 * 参考 emqx 官方官方例子
 * https://www.emqx.com/zh/blog/android-connects-mqtt-using-kotlin
 *
 * @param mqttClient
 * @param topic
 * @param msg
 * @param qos
 * @param retained
 */
private fun publish(
    mqttClient: MqttAndroidClient?,
    topic: String,
    msg: String,
    qos: Int = 1,
    retained: Boolean = false
) {
    try {
        val message = MqttMessage()
        message.payload = msg.toByteArray()
        message.qos = qos
        message.isRetained = retained
        mqttClient?.publish(topic, message, null, object : IMqttActionListener {
            override fun onSuccess(asyncActionToken: IMqttToken?) {
                DebugUtil.debugLog("$msg published to $topic")
            }

            override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                DebugUtil.exceptionLog(exception)
            }
        })
    } catch (e: MqttException) {
        e.printStackTrace()
    }
}


private fun getMqttAndroidClient(
    context: Context,
    serverUrl: String,
    clientId: String
): MqttAndroidClient? {
    //2、创建Client对象
    try {
        return MqttAndroidClient(
            context,
            serverUrl,
            clientId
        ).apply {
            // 设置通用回调函数 (连上服务器)
            // 以下回调都在主线程中 (如果使用MqttClient,使用此回调里面的都是非主线程)
            setCallback(object : MqttCallbackExtended {
                // 连接成功
                override fun connectComplete(reconnect: Boolean, serverURI: String) {
                    DebugUtil.debugLog("connectComplete: $reconnect $serverURI")
                }

                // 断开连接
                override fun connectionLost(cause: Throwable) {
                    DebugUtil.debugLog("connectionLost: ${cause.message}")
                }

                // 得到的消息
                override fun messageArrived(topic: String, message: MqttMessage) {
                    val msg = message.payload
                    val str = String(msg)
                    DebugUtil.debugLog("messageArrived: $topic $str")
                    DebugUtil.toast("messageArrived: $topic $str")
                }

                // 发送消息成功后的回调
                override fun deliveryComplete(token: IMqttDeliveryToken) {
                    DebugUtil.debugLog("deliveryComplete: $token")
                }
            })

            // 连接
            connect(
                MqttConnectOptions().apply {
                    //断开后，是否自动连接
                    isAutomaticReconnect = false
                    //是否清空客户端的连接记录。若为true，则断开后，broker将自动清除该客户端连接信息
                    isCleanSession = true
                    //设置用户名。跟Client ID不同。用户名可以看做权限等级
                    userName = "Admin"
                    //设置登录密码
                    password = "123".toCharArray()
                    //设置超时时间，单位为秒
                    connectionTimeout = 60
                    //心跳时间，单位为秒。即多长时间确认一次Client端是否在线
                    keepAliveInterval = 60
                    //允许同时发送几条消息（未收到broker确认信息）
                    maxInflight = 10
                    //选择MQTT版本
                    mqttVersion = MqttConnectOptions.MQTT_VERSION_3_1_1
                },
                context,
                // 设置通用回调 (接收 topic)
                object : IMqttActionListener {
                    override fun onSuccess(asyncActionToken: IMqttToken?) {
                        DebugUtil.debugLog("onSuccess: $asyncActionToken")
                    }

                    override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
                        DebugUtil.exceptionLog(exception)
                    }
                })
        }

    } catch (e: MqttException) {
        DebugUtil.exceptionLog(e)
        return null
    }
}


/**
 * 参考 https://blog.csdn.net/Myfittinglife/article/details/114629133
 */
@Composable
@Preview(showSystemUi = true, showBackground = true)
fun TryMqttClient() {
    val context = LocalContext.current

    // 这个 getMqttAndroidClient 在 recompose 的时候会被无限调用
    // 包个 remember 就行了
    val mClient = remember {
        getMqttAndroidClient(
            context,
            "ws://broker.emqx.io:8083/mqtt",
            "mqtt-hello-world-android"
        )
    }

    val topic = "testtopic/android-hello-world"

    var message by remember {
        mutableStateOf("")
    }

    Column {
        Button(onClick = {
            try {
                mClient?.subscribe(topic, 0)
                DebugUtil.toast("subscribe topic \"$topic\" success")
            } catch (e: Exception) {
                DebugUtil.exceptionLog(e)
            }
        }) {
            Text(text = "subscribe topic : testtopic/android-hello-world")
        }


        TextField(value = message, onValueChange = { message = it })

        Button(onClick = {
            publish(mClient, topic, message, 0)
        }) {
            Text(text = "publish to topic : testtopic/android-hello-world")
        }

    }
}